#pragma once
#include <iostream>
#include <functional>
#include <sys/epoll.h>
#include <unordered_map>
#include <cassert>
#include <vector>
#include <cstring>
#include <thread>
#include <memory>
#include <sys/eventfd.h>
#include <mutex>
#include <unistd.h>
#include <sys/timerfd.h>
#include "log.hpp"
#include "timer_task.hpp"


namespace Muduo
{
    // class Poller;
    class EventLoop;
    class Channel
    {
    public:
        using EventCallback = std::function<void()>;
        Channel(EventLoop* loop,int fd):_loop(loop),_fd(fd),_events(0),_revents(0){}

        int Fd() {return _fd;}

        //获取想要监控的事件
        uint32_t Events()
        {
            return _events;
        }

        //设置实际就绪事件
        void SetREvents(uint32_t events)
        {
            _revents = events;
        }

        //设置可读回调函数
        void SetReadCallback(const EventCallback & cb)
        {
            _read_callback = cb;
        }

        //设置可写回调函数
        void SetWriteCallback(const EventCallback & cb)
        {
            _write_callback = cb;
        }

        //设置错误回调函数
        void SetErrorCallback(const EventCallback & cb)
        {
            _error_callback = cb;
        }

        //设置关闭回调函数
        void SetCloseCallback(const EventCallback & cb)
        {   
            _close_callback = cb;
        }

        //设置任意回调函数
        void SetEventCallback(const EventCallback & cb)
        {
            _event_callback = cb;
        }
        
        //当前是否监控了可读
        bool ReadAble()
        {
            return (_events&EPOLLIN);//可读
        }

        //当前是否监控了可写
        bool WriteAble()
        {
            return (_events&EPOLLOUT);//可写
        }

        //启动读事件监控
        void EnableRead()
        {
            _events|=EPOLLIN;
            Update();//添加到实际的EventLoop的事件监控中
        }

        //启动写事件监控
        void EnableWrite()
        {
            _events|=EPOLLOUT;
            Update();//添加到实际的EventLoop的事件监控中
        }

        //关闭读事件监控
        void DisableRead()
        {
            _events&=~EPOLLIN;
            Update();//在实际的EventLoop的事件监控中移除
        }

        //关闭写事件监控
        void DisableWrite()
        {
            _events &=~EPOLLOUT;
            Update();//在实际的EventLoop的事件监控中移除
        }

        //关闭对所有事件的监控
        void DisableAll()
        {
            _events = 0;
            Update();//在实际的EventLoop的事件监控中移除
        }

        //事件处理,一旦触发了事件,就调用这个函数,进行选择
        void HandleEvent()
        {
            //根据实际触发的事件
            if((_revents&EPOLLIN)||(_revents&EPOLLRDHUP)||(_revents&EPOLLPRI))//可读,连接断开,优先数据
            {
                if(_read_callback) _read_callback();
            }
            //有可能会释放连接的事件,一次只处理一个
            if(_revents&EPOLLOUT)//可写
            {
                if(_write_callback) _write_callback();
            }
            else if(_revents&EPOLLERR)//出错
            {
                if(_error_callback) _error_callback();
            }
            else if(_revents&EPOLLHUP)//挂断
            {
                if(_close_callback) _close_callback();
            }
            if(_event_callback) _event_callback();//刷新活跃度
        }

        //移除监控->从epoll中移除掉,调用EventLoop接口进行移除
        void Remove();

        //操作实际的监控事件
        void Update();

    private:
        // Poller* _poller;
        EventLoop* _loop;
        int _fd;
        uint32_t _events;//当前需要监控的事件
        uint32_t _revents;//当前链接实际触发的事件
        EventCallback _read_callback;//可读事件被触发的回调函数
        EventCallback _write_callback;//可写事件被触发的回调函数
        EventCallback _error_callback;//错误事件被触发的回调函数
        EventCallback _close_callback;//连接断开事件被触发的回调函数
        EventCallback _event_callback;//任意事件被触发的回调函数
    };
        
#define MAX_EPOLLEVENTS 1024
    //描述符IO事件监控模块
    class Poller
    {
    public:
        Poller()
        {
            _epfd = epoll_create(MAX_EPOLLEVENTS);
            if(_epfd<0)
            {
                ELOG("epoll create error!");
                abort();//退出程序
            }
        }

        //添加或修改监控事件
        void UpdateEvent(Channel * channel)
        {
            bool ret = HasChannel(channel);
            if(ret == false)//不存在
            {
                _channels.insert(std::make_pair(channel->Fd(),channel));
                return Update(channel,EPOLL_CTL_ADD);
            }
            return Update(channel,EPOLL_CTL_MOD);
        }

        //移除监控事件
        void RemoveEvent(Channel * channel)
        {
            std::unordered_map<int,Channel*>::iterator it = _channels.find(channel->Fd());
            if(it != _channels.end())
            {
                _channels.erase(it);
                Update(channel,EPOLL_CTL_DEL);
            }
        }

        //开始监控,返回活跃连接
        void Poll(std::vector<Channel*> * active)
        {
            // int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);
            int nfds = epoll_wait(_epfd,_evs,MAX_EPOLLEVENTS,-1);
            if(nfds<0)
            {
                if(errno == EINTR)//被信号打断了
                {
                    return;
                }
                ELOG("epoll wait error:%s",strerror(errno));
                abort();
            }
            for(int i = 0;i<nfds;i++)
            {
                std::unordered_map<int,Channel*>::iterator it = _channels.find(_evs[i].data.fd);
                assert(it != _channels.end());
                it->second->SetREvents(_evs[i].events);//设置实际就绪的事件
                active->push_back(it->second);
            }
        }

    private:
        //对epoll的直接操作
        void Update(Channel * channel,int op)
        {
            // int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
            int fd = channel->Fd();
            struct epoll_event ev;
            ev.data.fd = fd;
            ev.events = channel->Events();
            int ret = epoll_ctl(_epfd,op,fd,&ev);
            if(ret <0)
            {
                ELOG("epoll_ctl error!");
            }
        }

        //判断一个channel是否已经添加了事件监控
        bool HasChannel(Channel * channel)
        {
            std::unordered_map<int,Channel*>::iterator it = _channels.find(channel->Fd());
            if(it == _channels.end())
            {
                return false;
            }
            return true;
        }

    private:
        int _epfd;//epoll的操作描述符
        // typedef union epoll_data {
        //     void        *ptr;
        //     int          fd;
        //     uint32_t     u32;
        //     uint64_t     u64;
        // } epoll_data_t;

        // struct epoll_event {
        //     uint32_t     events;      /* Epoll events */
        //     epoll_data_t data;        /* User data variable */
        // };
        struct epoll_event _evs[MAX_EPOLLEVENTS];//监控时保存所有的活跃事件
        std::unordered_map<int,Channel*> _channels;
    };

    //时间轮
    class TimerWheel
    {
    public:
        using WeakTask = std::weak_ptr<TimerTask>;
        using PtrTask = std::shared_ptr<TimerTask>;
        TimerWheel(EventLoop * loop):
        _capacity(60),_tick(0),_wheel(_capacity),_loop(loop)
        ,_timerfd(CreateTimerfd()),_timer_channel(std::make_unique<Channel>(_loop,_timerfd))
        {
            _timer_channel->SetReadCallback(std::bind(&TimerWheel::OnTime,this));
            _timer_channel->EnableRead();//启动读事件
        }

        //定时器中有个_timers成员,定时器信息的操作有可能会在多线程中进行,因此需要考虑线程安全问题
        //如果不想加锁,就把对定期的所有操作,都放到一个线程中进行
        void TimerAdd(uint64_t id,uint32_t delay,const TaskFunc & cb);

        //刷新任务
        void TimerRefresh(uint64_t id);

        //取消任务
        void TimerCancel(uint64_t id);

        //这个接口只能在模块内,在对应的Eventloop线程内执行
        bool HasTimer(uint64_t id)
        {
            auto it = _timers.find(id);
            if(it == _timers.end())
            {
                return false;
            }
            return true;
        }

    private:
        void RemoveTimer(uint64_t id)
        {
            std::unordered_map<uint64_t,WeakTask>::iterator it = _timers.find(id);
            if(it != _timers.end())
            {
                _timers.erase(it);
            }
        }

        static int CreateTimerfd()
        {
            int timerfd  = timerfd_create(CLOCK_MONOTONIC,0);
            if(timerfd<0)
            {
                perror("timerfd_create error");
                abort();//异常退出程序
            }
            struct itimerspec itime;
            itime.it_value.tv_sec = 1;
            itime.it_value.tv_nsec = 0;//第一次超时时间为1s
            itime.it_interval.tv_sec = 1;
            itime.it_interval.tv_nsec = 0;//第一次超时后,每次超时的时间间隔
            timerfd_settime(timerfd,0,&itime,nullptr);
            return timerfd;
        }

        int ReadTimeFd()
        {
            uint64_t times;
            int ret = read(_timerfd,&times,8);
            if(ret<0)
            {
                ELOG("read timerfd error!");
                abort();
            }
            return times;
        }

        //让指针移动到下一步
        void RunTimerTask()
        {
            _tick = ++_tick%_capacity;
            _wheel[_tick].clear();//清空指定位置的数组,就会把数组中保存的所有对象释放,进行析构函数调用
        }

        void OnTime()
        {
            //根据实际超时次数,执行对应的超时任务
            int times = ReadTimeFd();
            for(int i = 0;i<times;i++)
            {
                RunTimerTask();
            }
        }

        //添加定时任务
        void TimerAddInLoop(uint64_t id,uint32_t delay,const TaskFunc & cb)
        {
            PtrTask pt(new TimerTask(id,delay,cb));
            pt->SetRelease(std::bind(&TimerWheel::RemoveTimer,this,id));
            int pos = (_tick+delay)%_capacity;
            _wheel[pos].push_back(pt);
            _timers[id] = WeakTask(pt);
        }

        //刷新/延迟定时任务
        void TimerRefreshInLoop(uint64_t id)
        {
            std::unordered_map<uint64_t,WeakTask>::iterator it= _timers.find(id);
            if(it == _timers.end())
            {
                return;//没有定时任务,直接返回
            }
            //找到对应id的定时任务
            PtrTask pt = it->second.lock();//获取weak_ptr的shared_ptr
            uint32_t delay = pt->DelayTime();//获取延迟时间
            int pos = (_tick+delay)%_capacity;
            _wheel[pos].push_back(pt);
        }

        //取消定时任务
        void TimerCancelInLoop(uint64_t id)
        {
            std::unordered_map<uint64_t,WeakTask>::iterator it = _timers.find(id);
            if(it == _timers.end())
            {
                return;//没有对应的定时任务
            }
            PtrTask pt = it->second.lock();//获取weak_ptr的shared_ptr
            if(pt) pt->Cancel();
        }
    private:
        int _tick;//当前的指针,表示指向的位置,指向哪里,就释放哪里
        int _capacity;//表盘的最大数量(最大延迟时间)
        std::vector<std::vector<PtrTask>> _wheel;
        std::unordered_map<uint64_t,WeakTask> _timers;
        EventLoop * _loop;
        int _timerfd;//定时器描述符->可读事件回调就是读取计数器,执行定时任务
        std::unique_ptr<Channel> _timer_channel;//定时器对应的Channel
    };

    class EventLoop
    {
    public:
        using Functor = std::function<void()>;
        EventLoop():_thread_id(std::this_thread::get_id()),
        _event_fd(CreateEventFd()),_event_channel(std::make_unique<Channel>(this,_event_fd))
        ,_timer_wheel(this)
        {
            //给eventfd添加可读事件回调函数,读取eventfd事件通知次数
            _event_channel->SetReadCallback(std::bind(&EventLoop::ReadEventFd,this));
            //启动eventfd的读事件监控
            _event_channel->EnableRead();
        }

        void Start()
        {
            while(true)
            {
                //事件监控,获取活跃链接
                std::vector<Channel*> actives;
                _poller.Poll(&actives);
                //事件处理
                for(auto & channel:actives)
                {
                    channel->HandleEvent();
                }
                //执行任务
                RunAllTask();
            }
        }

        //用于判断当前线程是否是EventLoop对应的线程
        bool IsInLoop()
        {
            return (_thread_id == std::this_thread::get_id());
        }

        void AssertInLoop()
        {
            assert(_thread_id == std::this_thread::get_id());
        }
        
        //假设有一个work线程池
        //判断将要执行的任务是否处于当前线程中,如果是则执行,不是则放入队列
        void RunInLoop(const Functor & cb)
        {
            if(IsInLoop())
            {
                cb();
            }
            else 
            {
                QueueInLoop(cb);
            }
        }
        
        //将任务压入队列中
        void QueueInLoop(const Functor & cb)
        {
            {
                std::unique_lock<std::mutex> _lock(_mutex);
                _tasks.push_back(cb);
            }
            //唤醒有可能因为没有事件就绪而导致的epoll阻塞
            WeakUpEventFd();
        }

        //添加/修改描述符的事件监控
        void UpdateEvent(Channel * channel)
        {
            return _poller.UpdateEvent(channel);
        }

        //移除描述符的监控
        void RemoveEvent(Channel * channel)
        {
            return _poller.RemoveEvent(channel);
        }

        //添加定时任务
        void TimerAdd(uint64_t id,uint32_t delay,const TaskFunc& cb)
        {
            return _timer_wheel.TimerAdd(id,delay,cb);
        }

        //刷新定时任务
        void TimerRefresh(uint64_t id)
        {
            return _timer_wheel.TimerRefresh(id);
        }

        //取消定时任务
        void TimerCancel(uint64_t id)
        {
            return _timer_wheel.TimerCancel(id);
        }

        //是否存在某个定时任务
        bool HasTimer(uint64_t id)
        {
            return _timer_wheel.HasTimer(id);
        }
    private:
        //执行任务池中的所有任务
        void RunAllTask()
        {
            std::vector<Functor> functor;
            {
                std::unique_lock<std::mutex> _lock(_mutex);
                _tasks.swap(functor);
            }
            for(auto & f:functor)
            {
                f();
            }
        }

        //创建eventfd
        static int CreateEventFd()
        {
            int efd = eventfd(0,EFD_CLOEXEC|EFD_NONBLOCK);
            if(efd<0)
            {
                ELOG("create eventfd error!");
                abort();//创建失败,让程序异常退出
            }
            return efd;
        }

        //读取eventfd
        void ReadEventFd()
        {
            uint64_t res = 0;
            int ret = read(_event_fd,&res,sizeof(res));
            if(ret<0)
            {
                if(errno == EINTR||errno==EAGAIN) return;
                ELOG("read eventfd error!");
                abort();//让程序异常退出
            }
        }

        //唤醒eventfd
        void WeakUpEventFd()
        {
            uint64_t val = 1;
            int ret = write(_event_fd,&val,sizeof(val));
            if(ret<0)
            {
                if(errno == EINTR) return;
                ELOG("read eventfd error!");
                abort();
            }
        }
    private:
        std::thread::id _thread_id;//线程id
        int _event_fd;//eventfd唤醒IO事件监控有可能导致的阻塞
        std::unique_ptr<Channel> _event_channel;
        Poller _poller;//进行描述符的事件监控
        std::vector<Functor> _tasks;//任务池
        std::mutex _mutex;//实现任务池操作的线程安全
        TimerWheel _timer_wheel;//定时器模块
    };

    void Channel::Remove()
    {
        _loop->RemoveEvent(this);
    }

    void Channel::Update()
    {
        _loop->UpdateEvent(this);
    }

    void TimerWheel::TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &cb) 
    {
        _loop->RunInLoop(std::bind(&TimerWheel::TimerAddInLoop, this, id, delay, cb));
    }
    void TimerWheel::TimerRefresh(uint64_t id)
    {
        _loop->RunInLoop(std::bind(&TimerWheel::TimerRefreshInLoop,this,id));
    }
    void TimerWheel::TimerCancel(uint64_t id)
    {
        _loop->RunInLoop(std::bind(&TimerWheel::TimerCancelInLoop,this,id));
    }
}